From 98e076b51ea05fae38d75514f0144b68ff4aabfd Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 6 Apr 2019 02:40:29 +0200 Subject: [PATCH] rgba: Add gdk_rgba_parser_parse() This function is a (private) function to parse a GdkRGBA accoridng to the CSS specs. We should probably use it for gdk_rgba_parse(), but that would change the syntax we accept there... This also introduces a dependency of libgdk on libgtkcss. So far, no users for this function exist. --- gdk/gdkrgba.c | 184 ++++++++++++++++++++++++++++++++++++++++++- gdk/gdkrgbaprivate.h | 33 ++++++++ gdk/meson.build | 5 +- 3 files changed, 219 insertions(+), 3 deletions(-) create mode 100644 gdk/gdkrgbaprivate.h diff --git a/gdk/gdkrgba.c b/gdk/gdkrgba.c index 8e36523dc2..b52e0254e6 100644 --- a/gdk/gdkrgba.c +++ b/gdk/gdkrgba.c @@ -23,7 +23,9 @@ */ #include "config.h" -#include "gdkrgba.h" + +#include "gdkrgbaprivate.h" + #include #include #include @@ -393,3 +395,183 @@ gdk_rgba_to_string (const GdkRGBA *rgba) alpha); } } + +static gboolean +parse_color_channel_value (GtkCssParser *parser, + double *value, + gboolean is_percentage) +{ + if (is_percentage) + { + if (!gtk_css_parser_consume_percentage (parser, value)) + return FALSE; + + *value = CLAMP (*value, 0.0, 100.0) / 100.0; + return TRUE; + } + else + { + if (!gtk_css_parser_consume_number (parser, value)) + return FALSE; + + *value = CLAMP (*value, 0.0, 255.0) / 255.0; + return TRUE; + } +} + +static guint +parse_color_channel (GtkCssParser *parser, + guint arg, + gpointer data) +{ + GdkRGBA *rgba = data; + + switch (arg) + { + case 0: + /* We abuse rgba->alpha to store if we use percentages or numbers */ + if (gtk_css_token_is (gtk_css_parser_get_token (parser), GTK_CSS_TOKEN_PERCENTAGE)) + rgba->alpha = 1.0; + else + rgba->alpha = 0.0; + + if (!parse_color_channel_value (parser, &rgba->red, rgba->alpha != 0.0)) + return 0; + return 1; + + case 1: + if (!parse_color_channel_value (parser, &rgba->green, rgba->alpha != 0.0)) + return 0; + return 1; + + case 2: + if (!parse_color_channel_value (parser, &rgba->blue, rgba->alpha != 0.0)) + return 0; + return 1; + + case 3: + if (!gtk_css_parser_consume_number (parser, &rgba->alpha)) + return 0; + + rgba->alpha = CLAMP (rgba->alpha, 0.0, 1.0); + return 1; + + default: + g_assert_not_reached (); + return 0; + } +} + +static gboolean +rgba_init_chars (GdkRGBA *rgba, + const char s[8]) +{ + guint i; + + for (i = 0; i < 8; i++) + { + if (!g_ascii_isxdigit (s[i])) + return FALSE; + } + + rgba->red = (g_ascii_xdigit_value (s[0]) * 16 + g_ascii_xdigit_value (s[1])) / 255.0; + rgba->green = (g_ascii_xdigit_value (s[2]) * 16 + g_ascii_xdigit_value (s[3])) / 255.0; + rgba->blue = (g_ascii_xdigit_value (s[4]) * 16 + g_ascii_xdigit_value (s[5])) / 255.0; + rgba->alpha = (g_ascii_xdigit_value (s[6]) * 16 + g_ascii_xdigit_value (s[7])) / 255.0; + + return TRUE; +} + +gboolean +gdk_rgba_parser_parse (GtkCssParser *parser, + GdkRGBA *rgba) +{ + const GtkCssToken *token; + + token = gtk_css_parser_get_token (parser); + if (gtk_css_token_is_function (token, "rgb")) + { + if (!gtk_css_parser_consume_function (parser, 3, 3, parse_color_channel, rgba)) + return FALSE; + + rgba->alpha = 1.0; + return TRUE; + } + else if (gtk_css_token_is_function (token, "rgba")) + { + return gtk_css_parser_consume_function (parser, 4, 4, parse_color_channel, rgba); + } + else if (gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_ID) || + gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_UNRESTRICTED)) + { + const char *s = token->string.string; + + switch (strlen (s)) + { + case 3: + if (!rgba_init_chars (rgba, (char[8]) {s[0], s[0], s[1], s[1], s[2], s[2], 'F', 'F' })) + { + gtk_css_parser_error_value (parser, "Hash code is not a valid hex color."); + return FALSE; + } + break; + + case 4: + if (!rgba_init_chars (rgba, (char[8]) {s[0], s[0], s[1], s[1], s[2], s[2], s[3], s[3] })) + { + gtk_css_parser_error_value (parser, "Hash code is not a valid hex color."); + return FALSE; + } + break; + + case 6: + if (!rgba_init_chars (rgba, (char[8]) {s[0], s[1], s[2], s[3], s[4], s[5], 'F', 'F' })) + { + gtk_css_parser_error_value (parser, "Hash code is not a valid hex color."); + return FALSE; + } + break; + + case 8: + if (!rgba_init_chars (rgba, s)) + { + gtk_css_parser_error_value (parser, "Hash code is not a valid hex color."); + return FALSE; + } + break; + + default: + gtk_css_parser_error_value (parser, "Hash code is not a valid hex color."); + return FALSE; + break; + } + + gtk_css_parser_consume_token (parser); + return TRUE; + } + else if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT)) + { + if (gtk_css_token_is_ident (token, "transparent")) + { + *rgba = (GdkRGBA) { 0, 0, 0, 0 }; + } + else if (gdk_rgba_parse (rgba, token->string.string)) + { + /* everything's fine */ + } + else + { + gtk_css_parser_error_syntax (parser, "\"%s\" is not a valid color name.", token->string.string); + return FALSE; + } + + gtk_css_parser_consume_token (parser); + return TRUE; + } + else + { + gtk_css_parser_error_syntax (parser, "Expected a valid color."); + return FALSE; + } +} + diff --git a/gdk/gdkrgbaprivate.h b/gdk/gdkrgbaprivate.h new file mode 100644 index 0000000000..58470e04c9 --- /dev/null +++ b/gdk/gdkrgbaprivate.h @@ -0,0 +1,33 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 2010, Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef __GDK_RGBA_PRIVATE_H__ +#define __GDK_RGBA_PRIVATE_H__ + +#include "gdkrgba.h" + +#include + +#include "gtk/css/gtkcssparserprivate.h" + + +gboolean gdk_rgba_parser_parse (GtkCssParser *parser, + GdkRGBA *rgba); + +G_END_DECLS + +#endif diff --git a/gdk/meson.build b/gdk/meson.build index 44170dbae8..b2bf69620a 100644 --- a/gdk/meson.build +++ b/gdk/meson.build @@ -224,7 +224,8 @@ endif # FIXME: might have to add '-xobjective-c' to c_args for quartz backend? libgdk = static_library('gdk', sources: [gdk_sources, gdk_backends_gen_headers, gdkconfig], - dependencies: gdk_deps, + dependencies: gdk_deps + [libgtk_css_dep], + link_with: [libgtk_css, ], include_directories: [confinc, gdkx11_inc, wlinc], c_args: [ '-DGDK_COMPILATION', @@ -239,4 +240,4 @@ libgdk = static_library('gdk', libgdk_dep = declare_dependency( sources: ['gdk.h', gdkconfig, gdkenum_h], include_directories: [confinc, gdkx11_inc, wlinc], - dependencies: gdk_deps) + dependencies: gdk_deps + [libgtk_css_dep]) -- 2.30.2